/*
    $Header: /Windows/Shell/ShellExt.root/ShellExt/src/CShTerm.cpp 1     08-01-05 0:08 Ken $
    $Log: /Windows/Shell/ShellExt.root/ShellExt/src/CShTerm.cpp $
 * 
 * 1     08-01-05 0:08 Ken
*/


#include "stdafx.h"

#include <list>

#include "ShellExt.h"
#include "..\Src\CShTerm.h"

using namespace std;


extern HINSTANCE g_hInstance;


CShTerm::CShTerm()
    :CIShlCntxMenuImp()
{
    m_fFocus=FALSE;
    m_fSny2E=TRUE;
    m_fSny2C=TRUE;
    m_pInputObjSite=NULL;
    m_pFrameWB=NULL;
    m_hWnd=NULL;
    m_pcnslWnd=NULL;
}



///////////////////////////////////////////////////////////////////////////
//
// IDeskBand implementation
//
STDMETHODIMP CShTerm::GetBandInfo(DWORD dwBandID, DWORD dwViewMode, DESKBANDINFO* pdbi)
{
    if(pdbi)
    {
        m_dwBandID = dwBandID;
        m_dwViewMode = dwViewMode;

        if(pdbi->dwMask & DBIM_MINSIZE)
        {
            pdbi->ptMaxSize.x = 100;
            pdbi->ptMaxSize.y = 50;
        }

        if(pdbi->dwMask & DBIM_MAXSIZE)
        {
            pdbi->ptMaxSize.x = -1;
            pdbi->ptMaxSize.y = -1;
        }

        if(pdbi->dwMask & DBIM_INTEGRAL)
        {
            pdbi->ptIntegral.x = 1;
            pdbi->ptIntegral.y = 1;
        }

        if(pdbi->dwMask & DBIM_ACTUAL)
        {
            pdbi->ptActual.x = 1000;
            pdbi->ptActual.y = 500;
        }

        if(pdbi->dwMask & DBIM_TITLE)
        {
            lstrcpyW(pdbi->wszTitle, L"ShTerm");
        }

        if(pdbi->dwMask & DBIM_MODEFLAGS)
        {
            pdbi->dwModeFlags = DBIMF_NORMAL|DBIMF_VARIABLEHEIGHT;
        }

        if(pdbi->dwMask & DBIM_BKCOLOR)
        {
        //Use the default background color by removing this flag.
    //    pdbi->dwMask &= ~DBIM_BKCOLOR;
        }

        return S_OK;
    }
    return E_INVALIDARG;
}

///////////////////////////////////////////////////////////////////////////
//
// IDockingWindow Implementation
//
STDMETHODIMP CShTerm::ShowDW(BOOL fShow)
{
    if(m_hWnd)
    {
        if(fShow)
        {
            ShowWindow(m_hWnd, SW_SHOW);
        }
        else
        {
            ShowWindow(m_hWnd, SW_HIDE);
        }
    }
    return S_OK;
}

STDMETHODIMP CShTerm::CloseDW(DWORD dwReserved)
{
    ShowDW(FALSE);

    if(IsWindow(m_hWnd))
    {
        DestroyWindow(m_hWnd);
    }

    m_hWnd = NULL;

    return S_OK;
}

/*
    This method is never called for Band Objects.
*/
STDMETHODIMP CShTerm::ResizeBorderDW(   LPCRECT prcBorder,
                                          IUnknown* punkSite,
                                          BOOL fReserved)
{
  return E_NOTIMPL;
}

///////////////////////////////////////////////////////////////////////////
//
// IOleWindow Implementation
//
STDMETHODIMP CShTerm::GetWindow(HWND *phWnd)
{
    *phWnd = m_hWnd;
    return S_OK;
}

STDMETHODIMP CShTerm::ContextSensitiveHelp(BOOL fEnterMode)
{
    return E_NOTIMPL;
}

///////////////////////////////////////////////////////////////////////////
//
// IObjectWithSite implementations
//

STDMETHODIMP CShTerm::SetSite(IUnknown* punkSite)
{
    //If a site is being held, release it.
    if(m_pInputObjSite)
    {
        m_pInputObjSite->Release();
        m_pInputObjSite = NULL;
    }

    if(m_pFrameWB)
    {
        DispEventUnadvise(m_pFrameWB);
        m_pFrameWB->Release();
        m_pFrameWB = NULL;
    }

    //If punkSite is not NULL, a new site is being set.
    if(punkSite)
    {
        if(NULL!=m_pcnslWnd)
        {
            delete m_pcnslWnd;
            m_pcnslWnd=NULL;
        }

        //Get the parent window.
        IOleWindow  *pOleWindow;
        if(SUCCEEDED(punkSite->QueryInterface(IID_IOleWindow, (LPVOID*)&pOleWindow)))
        {
            pOleWindow->GetWindow(&m_hWndParent);
            pOleWindow->Release();
        }

        if(!m_hWndParent)
            return E_FAIL;

        if(NULL==RegisterAndCreateWindow(m_hWndParent))
            return E_FAIL;

        //Get and keep the IInputObjectSite pointer.
        if(FAILED(punkSite->QueryInterface(IID_IInputObjectSite, (LPVOID*)&m_pInputObjSite)))
        {
            return E_FAIL;
        }

        IOleCommandTarget* pCmdTarget = NULL;
        HRESULT hr = punkSite->QueryInterface(IID_IOleCommandTarget, (LPVOID*)&pCmdTarget);
        if (SUCCEEDED(hr))
        {
            IServiceProvider* pSP;
            hr = pCmdTarget->QueryInterface(IID_IServiceProvider, (LPVOID*)&pSP);
            pCmdTarget->Release();
            if (SUCCEEDED(hr))
            {
                hr = pSP->QueryService(SID_SWebBrowserApp, IID_IWebBrowser2, (LPVOID*)&m_pFrameWB);
                pSP->Release();
                if(NULL!=m_pFrameWB)
                {
                    DispEventAdvise(m_pFrameWB);
                }
            }

        }
    }
    else
    {
        if(NULL!=m_pcnslWnd)
        {
            delete m_pcnslWnd;
            m_pcnslWnd=NULL;
        }
    }

    return S_OK;
}

STDMETHODIMP CShTerm::GetSite(REFIID riid, LPVOID *ppvReturn)
{
    *ppvReturn = NULL;

    if(m_pInputObjSite)
        return m_pInputObjSite->QueryInterface(riid, ppvReturn);

    return E_FAIL;
}

///////////////////////////////////////////////////////////////////////////
//
// IInputObject Implementation
//

STDMETHODIMP CShTerm::UIActivateIO(BOOL fActivate, LPMSG pMsg)
{
    m_fFocus = fActivate;

    if(fActivate){
///           SetFocus(m_cCmdStubWnd.GetWnd());
    }

    return S_OK;
}

STDMETHODIMP CShTerm::HasFocusIO(void)
{
    if(m_fFocus)
        return S_OK;

    return S_FALSE;
}

//TODO: add accelerateor key process
STDMETHODIMP CShTerm::TranslateAcceleratorIO(LPMSG pMsg)
{
    if( (WM_KEYDOWN==pMsg->message)
        && (VK_TAB==pMsg->wParam) )
    {
        return S_FALSE;
    }


   TranslateMessage(pMsg);
   DispatchMessage(pMsg);
   return S_OK;}

void _stdcall CShTerm::OnNavigateComplete2(IDispatch *pDisp, VARIANT *URL)
{
    CString cstrURL(*URL);
//    ATLTRACE(TEXT("OnNavigateComplete2:%s\r\n"), cstrURL.GetBuffer());
    if(FALSE!=m_fSny2C)
    {
        m_pcnslWnd->ChangDir(cstrURL.GetBuffer());
    }
}

const TCHAR* CShTerm::VGetMenuString(DWORD dwId)
{
    switch(dwId)
    {
    case 0:
        return TEXT("sync path to Console");
    case 1:
        return TEXT("sync path to Explorer");
    case 2:
        if(TRUE==m_fSny2C)
        {
            return TEXT("Disable path auto sync to Console");
        }
        return TEXT("Enable path auto sync to Console");
    case 3:
        if(TRUE==m_fSny2E)
        {
            return TEXT("Disable path auto sync to Explorer");
        }
        return TEXT("Enable path auto sync to Explorer");
    default:
        break;
    }

    ATLTRACE(TEXT("invalid memnu id:%dr\n"), dwId);
    return NULL;
}

BOOL CShTerm::VInvokeCommand(LPCMINVOKECOMMANDINFO pInfo, DWORD dwId)
{
    BOOL fRet=TRUE;

    switch(dwId)
    {
    case 0:
    {
        BSTR bstrUrl=NULL;
        m_pFrameWB->get_LocationURL(&bstrUrl);
        m_pcnslWnd->ChangDir(COLE2T(bstrUrl));
        SysFreeString(bstrUrl);
        break;
    }
    case 1:
    {
        TCHAR szDir[MAX_PATH];
        if(FALSE==m_pcnslWnd->GetDir(szDir))
        {
            return fRet;
        }
        BSTR bstr;
        bstr = T2BSTR(szDir);
        m_pFrameWB->Navigate( bstr, NULL, NULL, NULL, NULL);
        break;
    }
    case 2:
        if(TRUE==m_fSny2C)
        {
            m_fSny2C=FALSE;
        }
        else
        {
            m_fSny2C=TRUE;
        }
        break;
    case 3:
        if(TRUE==m_fSny2E)
        {
            m_fSny2E=FALSE;
        }
        else
        {
            m_fSny2E=TRUE;
        }
        break;
    default:
        ATLTRACE(TEXT("invalid memnu id:%dr\n"), dwId);
        fRet=FALSE;
        break;
    }

    return fRet;
}


BOOL CShTerm::RegisterAndCreateWindow(HWND hwndParent)
{
    ATLASSERT(hwndParent);

    //If the window class has not been registered, then do so.
    WNDCLASS wc;
    if(!GetClassInfo(g_hInstance, SHTERM_CLASS_NAME, &wc))
    {
        ZeroMemory(&wc, sizeof(wc));
        wc.style          = CS_HREDRAW | CS_VREDRAW;
        wc.lpfnWndProc    = (WNDPROC)CShTerm::WndProc;
        wc.cbClsExtra     = 0;
        wc.cbWndExtra     = 0;
        wc.hInstance      = g_hInstance;
        wc.hIcon          = NULL;
        wc.hCursor        = NULL;
        wc.hbrBackground  = NULL;
        wc.lpszMenuName   = NULL;
        wc.lpszClassName  = SHTERM_CLASS_NAME;

        if(!RegisterClass(&wc))
        {
            //If RegisterClass fails, CreateWindow below will fail.
            return FALSE;
        }
    }

    RECT  rc;
    GetClientRect(hwndParent, &rc);

    //Create the window. The WndProc will set m_hWnd.
    CreateWindowEx(0,
                               SHTERM_CLASS_NAME,
                               NULL,
                               WS_CHILD | WS_CLIPSIBLINGS| WS_CLIPCHILDREN,
                               rc.left, rc.top, rc.right - rc.left, rc.bottom - rc.top,
                               hwndParent,
                               NULL,
                               g_hInstance,
                               (LPVOID)this);

    // WM_NCCREATE will set m_hWnd
    return (NULL!=m_hWnd)?TRUE:FALSE;

}

LRESULT CALLBACK CShTerm::WndProc(HWND hWnd,
                                    UINT uMessage,
                                    WPARAM wParam,
                                    LPARAM lParam)
{
    CShTerm *pThis = (CShTerm*)GetWindowLong(hWnd, GWL_USERDATA);

    switch(uMessage)
    {
        case WM_NCCREATE:
        {
            LPCREATESTRUCT lpcs = (LPCREATESTRUCT)lParam;
            pThis = (CShTerm*)(lpcs->lpCreateParams);
            SetWindowLong(hWnd, GWL_USERDATA, (LONG)pThis);

            //set the window handle
            pThis->m_hWnd = hWnd;
        }
        break;

        case WM_CREATE:
            pThis->m_pcnslWnd=new ConsoleEmbWnd();
            if(FALSE==pThis->m_pcnslWnd->Create(CShTerm::CnslWndNotifyFn, pThis))
            {
                return -1;
            }
            SetParent(pThis->m_pcnslWnd->GetWindow(), hWnd);
            break;

        case WM_SIZE:
            pThis->m_pcnslWnd->MoveWindow(0, 0, LOWORD(lParam), HIWORD (lParam), TRUE);
            return 0;

        case WM_COMMAND:
            if(EN_KILLFOCUS==HIWORD (wParam))
            {
                pThis->m_fFocus=FALSE;
                if(pThis->m_pInputObjSite)
                {
                    return pThis->m_pInputObjSite->OnFocusChangeIS((IDockingWindow*)pThis, pThis->m_fFocus);
                }
            }
            else if(EN_SETFOCUS==HIWORD (wParam))
            {
                pThis->m_fFocus=TRUE;
                if(pThis->m_pInputObjSite)
                {
                    return pThis->m_pInputObjSite->OnFocusChangeIS((IDockingWindow*)pThis, pThis->m_fFocus);
                }
            }
            return 0;

        case WM_DESTROY:
            if(NULL!=pThis->m_pcnslWnd)
            {
                delete pThis->m_pcnslWnd;
                pThis->m_pcnslWnd=NULL;
            }
            break;
            
        default:
            break;

    }

    return DefWindowProc(hWnd, uMessage, wParam, lParam);
}

void CShTerm::CnslWndNotifyFn(void* cbCtx, DWORD dwCbType, VOID* para)
{
    ((CShTerm*)cbCtx)->CnslWndNotify(dwCbType, para);
}

void CShTerm::CnslWndNotify(DWORD dwCbType, VOID* para)
{
    if(dwCbType==CNSL_WND_CB_CMD_EXIT)
    {
        SendMessage(m_hWndParent, WM_CLOSE, 0, 0);
    }
    else if(dwCbType==CNSL_WND_CB_CD_DIR)
    {
		if(FALSE!=m_fSny2E)
		{
			TCHAR szDir[MAX_PATH];
			if(FALSE==m_pcnslWnd->GetDir(szDir))
			{
				return;
			}
			BSTR bstr;
			bstr = T2BSTR(szDir);
			m_pFrameWB->Navigate( bstr, NULL, NULL, NULL, NULL);
		}
    }
}

